Skip to content

Method: isValidJavaClassName(OWLAnnotation, ContextDefinition)

1: /**
2: * Copyright (C) 2016 Czech Technical University in Prague
3: * <p>
4: * This program is free software: you can redistribute it and/or modify it under
5: * the terms of the GNU General Public License as published by the Free Software
6: * Foundation, either version 3 of the License, or (at your option) any
7: * later version.
8: * <p>
9: * This program is distributed in the hope that it will be useful, but WITHOUT
10: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12: * details. You should have received a copy of the GNU General Public License
13: * along with this program. If not, see <http://www.gnu.org/licenses/>.
14: */
15: package cz.cvut.kbss.jopa.owl2java;
16:
17: import com.sun.codemodel.*;
18: import cz.cvut.kbss.jopa.CommonVocabulary;
19: import cz.cvut.kbss.jopa.model.annotations.*;
20: import cz.cvut.kbss.jopa.model.annotations.OWLAnnotationProperty;
21: import cz.cvut.kbss.jopa.model.annotations.OWLDataProperty;
22: import cz.cvut.kbss.jopa.model.annotations.OWLObjectProperty;
23: import cz.cvut.kbss.jopa.model.annotations.Properties;
24: import cz.cvut.kbss.jopa.model.ic.DataParticipationConstraint;
25: import cz.cvut.kbss.jopa.model.ic.ObjectParticipationConstraint;
26: import cz.cvut.kbss.jopa.owlapi.DatatypeTransformer;
27: import org.semanticweb.owlapi.model.*;
28: import org.semanticweb.owlapi.model.OWLClass;
29: import org.slf4j.Logger;
30: import org.slf4j.LoggerFactory;
31:
32: import java.io.File;
33: import java.io.IOException;
34: import java.util.*;
35:
36: import static cz.cvut.kbss.jopa.owl2java.Constants.*;
37:
38: public class JavaTransformer {
39:
40: private static final Logger LOG = LoggerFactory.getLogger(OWL2JavaTransformer.class);
41:
42: private static final String[] KEYWORDS = {"abstract",
43: "assert",
44: "boolean",
45: "break",
46: "byte",
47: "case",
48: "catch",
49: "char",
50: "class",
51: "const",
52: "continue",
53: "default",
54: "do",
55: "double",
56: "else",
57: "enum",
58: "extends",
59: "final",
60: "finally",
61: "float",
62: "for",
63: "goto",
64: "if",
65: "implements",
66: "import",
67: "instanceof",
68: "int",
69: "interface",
70: "long",
71: "native",
72: "new",
73: "package",
74: "private",
75: "protected",
76: "public",
77: "return",
78: "short",
79: "static",
80: "strictfp",
81: "super",
82: "switch",
83: "synchronized",
84: "this",
85: "throw",
86: "throws",
87: "transient",
88: "try",
89: "void",
90: "volatile",
91: "while"};
92:
93: private JDefinedClass voc;
94: private Map<OWLEntity, JFieldRef> entities = new HashMap<>();
95:
96: private Map<OWLClass, JDefinedClass> classes = new HashMap<>();
97:
98: private JFieldVar addField(final String name, final JDefinedClass cls,
99: final JType fieldType) {
100: String newName = name;
101:
102: int i = 0;
103: while (cls.fields().containsKey(newName)) {
104: newName = name + "" + (++i);
105: }
106:
107: final JFieldVar fvId = cls.field(JMod.PROTECTED, fieldType, newName);
108: final String fieldName = fvId.name().substring(0, 1).toUpperCase() + fvId.name().substring(1);
109: final JMethod mSetId = cls.method(JMod.PUBLIC, void.class, "set" + fieldName);
110: final JVar v = mSetId.param(fieldType, fvId.name());
111: mSetId.body().assign(JExpr._this().ref(fvId), v);
112: final JMethod mGetId = cls.method(JMod.PUBLIC, fieldType, "get" + fieldName);
113: mGetId.body()._return(fvId);
114: return fvId;
115: }
116:
117: public void generateModel(final OWLOntology ontology,
118: final ContextDefinition context, final String pkg, String targetDir, boolean withOWLAPI) {
119:
120: try {
121: final JCodeModel cm = new JCodeModel();
122: voc = cm._class(pkg + PACKAGE_SEPARATOR + VOCABULARY_CLASS);
123: generateVocabulary(ontology, cm, context, withOWLAPI);
124: _generateModel(ontology, cm, context, pkg + PACKAGE_SEPARATOR + MODEL_PACKAGE + PACKAGE_SEPARATOR);
125: writeOutModel(cm, targetDir);
126: } catch (JClassAlreadyExistsException e1) {
127: LOG.error("Transformation FAILED.", e1);
128: } catch (IOException e) {
129: LOG.error("File generation FAILED.", e);
130: }
131: }
132:
133: /**
134: * Generates only vocabulary of the loaded ontology.
135: *
136: * @param context Integrity constraints context, if null is supplied, the whole ontology is interpreted as
137: * integrity constraints.
138: * @param targetDir Directory into which the vocabulary file will be generated
139: * @param pkg Package
140: * @param withOWLAPI Whether OWLAPI-based IRIs of the generated vocabulary items should be created as well
141: */
142: public void generateVocabulary(final OWLOntology ontology, ContextDefinition context, String pkg, String targetDir,
143: boolean withOWLAPI) {
144: try {
145: final JCodeModel cm = new JCodeModel();
146: this.voc = cm._class(pkg + PACKAGE_SEPARATOR + VOCABULARY_CLASS);
147: generateVocabulary(ontology, cm, context, withOWLAPI);
148: writeOutModel(cm, targetDir);
149: } catch (JClassAlreadyExistsException e) {
150: LOG.error("Vocabulary generation FAILED, because the Vocabulary class already exists.", e);
151: } catch (IOException e) {
152: LOG.error("Vocabulary file generation FAILED.", e);
153: }
154: }
155:
156: private void writeOutModel(JCodeModel cm, String targetDir) throws IOException {
157: final File file = new File(targetDir);
158: file.mkdirs();
159: cm.build(file);
160: }
161:
162: private void _generateModel(final OWLOntology ontology, final JCodeModel cm,
163: final ContextDefinition context, final String pkg) {
164: LOG.info("Generating model ...");
165:
166: context.classes.add(ontology.getOWLOntologyManager().getOWLDataFactory().getOWLThing());
167:
168: for (final OWLClass clazz : context.classes) {
169: LOG.info(" Generating class '{}'.", clazz);
170: final JDefinedClass subj = ensureCreated(context, pkg, cm, clazz, ontology);
171:
172: for (final org.semanticweb.owlapi.model.OWLObjectProperty prop : context.objectProperties) {
173:
174: final IntegrityConstraintParserImpl.ClassObjectPropertyComputer comp = context.parser.new ClassObjectPropertyComputer(
175: clazz, prop,
176: ontology);
177:
178: if (OWL2JavaTransformer.Card.NO.equals(comp.getCard())) {
179: continue;
180: }
181:
182: JClass filler = ensureCreated(context, pkg, cm,
183: comp.getObject(), ontology);
184: final String fieldName = validJavaIDForIRI(prop.getIRI());
185:
186: switch (comp.getCard()) {
187: case ONE:
188: break;
189: case MULTIPLE:
190: filler = cm.ref(java.util.Set.class).narrow(filler);
191: break;
192: case SIMPLELIST:
193: case LIST:
194: filler = cm.ref(java.util.List.class).narrow(filler);
195: break;
196: }
197:
198: final JFieldVar fv = addField(fieldName, subj, filler);
199:
200: if (comp.getCard().equals(OWL2JavaTransformer.Card.SIMPLELIST)) {
201: fv.annotate(Sequence.class)
202: .param("type", SequenceType.simple);
203: }
204:
205:
206: fv.annotate(OWLObjectProperty.class).param("iri",
207: entities.get(prop));
208:
209: JAnnotationArrayMember use = null;
210: for (ObjectParticipationConstraint ic : comp
211: .getParticipationConstraints()) {
212: if (use == null) {
213: use = fv.annotate(ParticipationConstraints.class)
214: .paramArray("value");
215: }
216: JAnnotationUse u = use.annotate(
217: ParticipationConstraint.class).param(
218: // "owlClassIRI",
219: // ic.getSubject().getIRI().toString()).param(
220: // "owlPropertyIRI",
221: // ic.getPredicate().getIRI().toString()).param(
222: "owlObjectIRI", entities.get(ic.getObject()));
223: if (ic.getMin() != 0) {
224: u.param("min", ic.getMin());
225: }
226:
227: if (ic.getMax() != -1) {
228: u.param("max", ic.getMax());
229: }
230: }
231: }
232:
233: for (org.semanticweb.owlapi.model.OWLDataProperty prop : context.dataProperties) {
234: final IntegrityConstraintParserImpl.ClassDataPropertyComputer comp = context.parser
235: .getClassDataPropertyComputer(clazz, prop, ontology);
236:
237: if (OWL2JavaTransformer.Card.NO.equals(comp.getCard())) {
238: continue;
239: }
240:
241: final JType obj = cm._ref(DatatypeTransformer
242: .transformOWLType(comp.getFiller()));
243:
244: final String fieldName = validJavaIDForIRI(
245: prop.getIRI());
246:
247: JFieldVar fv;
248:
249: if (OWL2JavaTransformer.Card.MULTIPLE.equals(comp.getCard())) {
250: fv = addField(fieldName, subj, cm.ref(java.util.Set.class)
251: .narrow(obj));
252: } else if (OWL2JavaTransformer.Card.ONE.equals(comp.getCard())) {
253: fv = addField(fieldName, subj, obj);
254: } else {
255: assert false : "Unknown cardinality type";
256: continue;
257: }
258:
259: fv.annotate(OWLDataProperty.class).param("iri",
260: entities.get(prop));
261:
262: JAnnotationArrayMember use = null;
263: for (DataParticipationConstraint ic : comp
264: .getParticipationConstraints()) {
265: if (use == null) {
266: use = fv.annotate(ParticipationConstraints.class)
267: .paramArray("value");
268: }
269:
270: JAnnotationUse u = use.annotate(
271: ParticipationConstraint.class).param(
272: "owlObjectIRI", comp.getFiller().getIRI().toString());
273:
274: if (ic.getMin() != 0) {
275: u = u.param("min", ic.getMin());
276: }
277:
278: if (ic.getMax() != -1) {
279: u = u.param("max", ic.getMax());
280: }
281: }
282: }
283: }
284: }
285:
286: private void generateVocabulary(final OWLOntology o, final JCodeModel cm, ContextDefinition context,
287: boolean withOWLAPI) {
288: final Collection<OWLEntity> col = new HashSet<>();
289: col.add(o.getOWLOntologyManager().getOWLDataFactory().getOWLThing());
290: col.addAll(context.classes);
291: col.addAll(context.objectProperties);
292: col.addAll(context.dataProperties);
293: col.addAll(context.annotationProperties);
294: col.addAll(context.individuals);
295:
296: for (final OWLOntology s : o.getOWLOntologyManager().getOntologies()) {
297: IRI iri = s.getOntologyID().getOntologyIRI();
298: voc.field(JMod.PUBLIC | JMod.STATIC
299: | JMod.FINAL, String.class, "ONTOLOGY_IRI_" + validJavaIDForIRI(iri),
300: JExpr.lit(iri.toString()));
301: }
302:
303: for (final OWLEntity c : col) {
304: String prefix = "";
305:
306: if (c.isOWLClass()) {
307: prefix = "c_";
308: } else if (c.isOWLDatatype()) {
309: prefix = "d_";
310: } else if (c.isOWLDataProperty() || c.isOWLObjectProperty()
311: || c.isOWLAnnotationProperty()) {
312: prefix = "p_";
313: } else if (c.isOWLNamedIndividual()) {
314: prefix = "i_";
315: }
316:
317: String id = prefix + validJavaIDForIRI(c.getIRI());
318:
319: while (voc.fields().keySet().contains("s_" + id)) {
320: id += "_A";
321: }
322:
323: final String sFieldName = "s_" + id;
324:
325: final JFieldVar fv1 = voc.field(JMod.PUBLIC | JMod.STATIC
326: | JMod.FINAL, String.class, sFieldName,
327: JExpr.lit(c.getIRI().toString()));
328: if (withOWLAPI) {
329: voc.field(JMod.PUBLIC | JMod.STATIC | JMod.FINAL, IRI.class, id, cm
330: .ref(IRI.class).staticInvoke("create").arg(fv1));
331: }
332:
333: entities.put(c, voc.staticRef(fv1));
334: }
335: }
336:
337: private static String validJavaIDForIRI(final IRI iri) {
338: if (iri.getFragment() != null) {
339: return validJavaID(iri.getFragment());
340: } else {
341: int x = iri.toString().lastIndexOf("/");
342: return validJavaID(iri.toString().substring(x + 1));
343: }
344: }
345:
346:
347: private static String validJavaID(final String s) {
348: String res = s.trim().replace("-", "_").replace("'", "_quote_").replace(".", "_dot_").replace(',', '_');
349: if (Arrays.binarySearch(KEYWORDS, res) >= 0) {
350: res = "_" + res;
351: }
352: return res;
353: }
354:
355: private String javaClassId(OWLOntology ontology, OWLClass owlClass, ContextDefinition ctx) {
356: final Set<OWLAnnotation> annotations = owlClass.getAnnotations(ontology);
357: for (OWLAnnotation a : annotations) {
358: if (isValidJavaClassName(a, ctx)) {
359: if (a.getValue() instanceof OWLLiteral) {
360: return ((OWLLiteral) a.getValue()).getLiteral();
361: }
362: }
363: }
364: return validJavaIDForIRI(owlClass.getIRI());
365: }
366:
367: private JDefinedClass ensureCreated(final ContextDefinition ctx,
368: final String pkg, final JCodeModel cm, final OWLClass clazz,
369: final OWLOntology ontology) {
370: if (classes.containsKey(clazz)) {
371: return classes.get(clazz);
372: }
373:
374: JDefinedClass cls;
375:
376: String name = pkg + javaClassId(ontology, clazz, ctx);
377:
378: try {
379: cls = cm._class(name);
380:
381: cls.annotate(
382: cz.cvut.kbss.jopa.model.annotations.OWLClass.class)
383: .param("iri", entities.get(clazz));
384:
385: final JDocComment dc = cls.javadoc();
386: dc.add("This class was generated by the OWL2Java tool version " + VERSION);
387:
388: // if (clazz.equals(f.getOWLThing())) {
389: // RDFS label
390: final JClass ftLabel = cm.ref(String.class);
391: final JFieldVar fvLabel = addField("name", cls, ftLabel);
392: fvLabel.annotate(OWLAnnotationProperty.class).param("iri",
393: cm.ref(CommonVocabulary.class).staticRef("RDFS_LABEL"));
394:
395: // DC description
396: final JClass ftDescription = cm.ref(String.class);
397: final JFieldVar fvDescription = addField("description", cls, ftDescription);
398: fvDescription.annotate(OWLAnnotationProperty.class).param("iri",
399: cm.ref(CommonVocabulary.class).staticRef("DC_DESCRIPTION"));
400:
401: // @Types Set<String> types;
402: final JClass ftTypes = cm.ref(Set.class).narrow(String.class);
403: final JFieldVar fvTypes = addField("types", cls, ftTypes);
404: fvTypes.annotate(Types.class);
405:
406: // @Id public final String id;
407: final JClass ftId = cm.ref(String.class);
408: final JFieldVar fvId = addField("id", cls, ftId);
409: JAnnotationUse a = fvId.annotate(Id.class);
410:
411: a.param("generated", true);
412:
413: // @Properties public final Map<String,Set<String>> properties;
414: final JClass ftProperties = cm.ref(Map.class).narrow(
415: cm.ref(String.class),
416: cm.ref(Set.class).narrow(String.class));
417: final JFieldVar fvProperties = addField("properties", cls,
418: ftProperties);
419: fvProperties.annotate(Properties.class);
420: // }
421:
422: } catch (JClassAlreadyExistsException e) {
423: LOG.trace("Class already exists. Using the existing version. {}", e.getMessage());
424: cls = cm._getClass(name);
425: }
426: classes.put(clazz, cls);
427:
428: return cls;
429: }
430:
431: private boolean isValidJavaClassName(OWLAnnotation a, ContextDefinition ctx) {
432: // TODO Replace this hardcoded stuff with a configurable solution
433: return a.getProperty().getIRI()
434: .equals(IRI.create("http://krizik.felk.cvut.cz/ontologies/2009/ic.owl#javaClassName"));
435: // Annotation of annotation is currently not supported
436: // for (OWLAnnotation ctxAnn : a.getAnnotations()) {
437: // ctxAnn.getValue().accept(v);
438: // final String icContextName = v.getName();
439: // System.out.println("Context: " + icContextName);
440: // if (icContextName != null && icContextName.equals(ctx.name)) {
441: // return true;
442: // }
443: // }
444: }
445:
446: }